package hight;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest2 {
    // ReentrantLock可以用来替代Synchroized,在需要同步的代码块加锁，最后一定要释放所，否则其他线程永远
    // 可以使用Condition来替代wait和notify来进行线程之间的通讯，Condition只针对某一把锁
    // 一个Lock可以创建多个Condition，更加灵活
    // Lock的其他方法
    // tryLock() 尝试获得锁，返回true/false
    // tryLock(timeout,unit) 在给定时间内尝试获得锁
    // siFair() 判断是否为公平锁
    // isLocked() 当前线程是否持有锁
    // lock.getHoldCount() 持有锁的数量，只能在当前调用线程内容使用，不能在其他线程中使用

    private Lock lock = new ReentrantLock();
    // 公平锁
    // ReentrantLock的构造函数可以传入一个boolean参数，用来指定公平/非公平模式，默认模式是 false (非公平)，非公平效率更高
    // private Lock lock = new ReentrantLock(true);
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    public void run1() {
        try {
            lock.lock();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "进入等待状态..");
            Thread.sleep(3000);
            System.out.println("当前线程" + Thread.currentThread().getName() + "释放锁。。");
            c1.await();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run1 继续执行。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
    public void run2() {
        try {
            lock.lock();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run2 进入等待状态..");
            System.out.println("当前线程" + Thread.currentThread().getName() + "释放锁。。");
            c1.await();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run2 继续执行。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
    public void run3() {
        try {
            lock.lock();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run3 进入等待状态..");
            System.out.println("当前线程" + Thread.currentThread().getName() + "释放锁。。");
            c2.await();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run3 继续执行。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
    public void run4() {
        try {
            lock.lock();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run4唤醒...");
            c1.signalAll();
            System.out.println("当前线程" + Thread.currentThread().getName() + "run4 end");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }

    }
    public void run5() {
        try {
            lock.lock();
            System.out.println("当前线程：" + Thread.currentThread().getName() + "run5唤醒...");
            c2.signal();
            System.out.println("当前线程" + Thread.currentThread().getName() + "run5 end");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }

    }
    public static void main(String[] args) {
        ReentrantLockTest2 reentrantLockTest1 = new ReentrantLockTest2();
        Thread t1 = new Thread(() ->{
            reentrantLockTest1.run1();
        },"t1");
        Thread t2 = new Thread(() ->{
            reentrantLockTest1.run2();
        },"t2");
        Thread t3 = new Thread(() ->{
            reentrantLockTest1.run3();
        },"t3");
        Thread t4 = new Thread(() ->{
            reentrantLockTest1.run4();
        },"t4");
        Thread t5 = new Thread(() ->{
            reentrantLockTest1.run5();
        },"t5");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
